// ==UserScript==
// @name         通用验证码自动识别框架
// @namespace    your_namespace
// @version      1.0
// @description  插件化验证码识别框架，支持多种网站规则
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @connect      10.0.0.3
// @connect      api.nonex.top
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // ====================== 核心模块 ======================
    const API_URLS = {
        DEFAULT: 'https://api.nonex.top/captcha/code',
    };

    // 验证码识别器
    const CaptchaRecognizer = {
        /**
         * 识别验证码图片
         * @param {string} base64Data - 图片base64数据
         * @param {string} apiUrl - 使用的API地址
         * @returns {Promise<string>} 识别结果
         */
        recognize: async function(base64Data, apiUrl = API_URLS.DEFAULT) {
            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: "POST",
                    url: apiUrl,
                    headers: {"Content-Type": "application/json"},
                    data: JSON.stringify({ ImageBase64: base64Data }),
                    onload: function(response) {
                        try {
                            const result = JSON.parse(response.responseText);
                            if (result.status === 'success') {
                                resolve(result.result);
                            } else {
                                reject(new Error(`API error: ${result.message || 'Unknown error'}`));
                            }
                        } catch (e) {
                            reject(new Error('Invalid API response'));
                        }
                    },
                    onerror: reject
                });
            });
        },

        /**
         * 获取网络图片并转为base64
         * @param {string} url - 图片URL
         * @returns {Promise<string>} base64数据
         */
        fetchImageAsBase64: function(url) {
            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: "GET",
                    url: url,
                    responseType: "blob",
                    onload: function(res) {
                        if (res.status !== 200) {
                            reject(new Error(`Image load failed: ${res.status}`));
                            return;
                        }
                        const reader = new FileReader();
                        reader.onloadend = () => resolve(reader.result.split(',')[1]);
                        reader.readAsDataURL(res.response);
                    },
                    onerror: reject
                });
            });
        },

        /**
         * 设置输入框值并触发事件
         * @param {HTMLInputElement} input - 目标输入框
         * @param {string} value - 要设置的值
         */
        setInputValue: function(input, value) {
            input.value = value;
            ['input', 'change'].forEach(eventType => {
                input.dispatchEvent(new Event(eventType, {
                    bubbles: true,
                    cancelable: true
                }));
            });
        }
    };

    // ====================== 规则管理系统 ======================
    const RuleManager = {
        rules: [],
        currentRule: null,

        /**
         * 注册新规则
         * @param {Object} rule - 规则对象
         */
        registerRule: function(rule) {
            if (!rule.name || !rule.match) {
                console.error('Invalid rule format');
                return;
            }
            this.rules.push(rule);
            console.log(`Registered rule: ${rule.name}`);
        },

        /**
         * 匹配当前URL对应的规则
         */
        matchRule: function() {
            const url = window.location.href;
            return this.rules.find(rule => {
                try {
                    return rule.match instanceof RegExp 
                        ? rule.match.test(url)
                        : url.includes(rule.match);
                } catch (e) {
                    console.error(`Rule matching error: ${e}`);
                    return false;
                }
            });
        },

        /**
         * 初始化当前匹配的规则
         */
        initMatchedRule: function() {
            this.currentRule = this.matchRule();
            if (!this.currentRule) return;

            console.log(`Matched rule: ${this.currentRule.name}`);
            this.observeDOM();
        },

        /**
         * 监听DOM变化以处理动态加载
         */
        observeDOM: function() {
            const observer = new MutationObserver(() => {
                this.tryInitRule(this.currentRule);
            });
            
            observer.observe(document.body, {
                childList: true,
                subtree: true,
                attributes: false
            });
            
            // 立即尝试初始化
            setTimeout(() => this.tryInitRule(this.currentRule), 100);
        },

        /**
         * 尝试初始化规则
         * @param {Object} rule - 当前规则
         */
        tryInitRule: function(rule) {
            try {
                const input = rule.getInputElement();
                if (!input || input.dataset.autofillBound) return;
                
                // 标记已处理
                input.dataset.autofillBound = 'true';
                
                // 绑定事件
                const handler = async () => {
                    try {
                        const base64 = await rule.getCaptchaImage();
                        if (!base64) throw new Error('Failed to get captcha image');
                        
                        const apiUrl = rule.apiUrl || API_URLS.DEFAULT;
                        const code = await CaptchaRecognizer.recognize(base64, apiUrl);
                        
                        CaptchaRecognizer.setInputValue(input, code);
                        
                        // 单次执行后解除绑定
                        if (rule.once) {
                            input.removeEventListener('focus', handler);
                        }
                    } catch (e) {
                        console.error(`[${rule.name}] Error:`, e);
                    }
                };
                
                input.addEventListener('focus', handler);
                console.log(`Bound to input for rule: ${rule.name}`);
                
            } catch (e) {
                console.error(`Rule init error: ${e}`);
            }
        }
    };

    // ====================== 内置规则 ======================
    
    // COLLEGES规则
    RuleManager.registerRule({
        name: 'COLLEGES',
        match: /your_colleges_domain\.com/, // 替换为实际域名
        once: false,
        apiUrl: API_URLS.DEFAULT,
        getInputElement: () => document.getElementById('captchatext'),
        getCaptchaImage: async function() {
            const img = document.getElementById('captcha');
            if (!img) return null;
            
            if (img.src.startsWith('data:')) {
                return img.src.split(',')[1];
            }
            return CaptchaRecognizer.fetchImageAsBase64(img.src);
        }
    });

    // Gitea规则
    RuleManager.registerRule({
        name: 'Gitea',
        match: 'https://gitea.nonex.top',
        once: false,
        apiUrl: API_URLS.DEFAULT,
        getInputElement: () => document.querySelector('input[name="captcha"]'),
        getCaptchaImage: async function() {
            const img = document.querySelector('img.captcha-img');
            if (!img) return null;
            
            // 添加时间戳防止缓存
            const freshUrl = img.src.split('?')[0] + '?t=' + Date.now();
            return CaptchaRecognizer.fetchImageAsBase64(freshUrl);
        }
    });

    // NK规则
    RuleManager.registerRule({
        name: 'NK',
        match: /your_nk_domain\.com/, // 替换为实际域名
        once: true,
        apiUrl: DEFAULT,
        getInputElement: () => 
            document.querySelector('div.el-form-item:nth-child(4) > div > div > input'),
        getCaptchaImage: async function() {
            const canvas = document.querySelector('.poi');
            if (!canvas) return null;
            
            try {
                return canvas.toDataURL('image/jpeg', 0.8).split(',')[1];
            } catch (e) {
                throw new Error('Canvas conversion failed');
            }
        }
    });

    // ====================== 初始化 ======================
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => RuleManager.initMatchedRule());
    } else {
        RuleManager.initMatchedRule();
    }

    // ====================== 扩展接口 ======================
    window.CaptchaAutoFill = {
        registerRule: RuleManager.registerRule.bind(RuleManager),
        recognize: CaptchaRecognizer.recognize,
        utils: {
            fetchImageAsBase64: CaptchaRecognizer.fetchImageAsBase64,
            setInputValue: CaptchaRecognizer.setInputValue
        }
    };

    console.log('Captcha AutoFill framework initialized');
})();